package com.cmcc.packet.entity;/*
 * Copyright © 2019, 2020, 2021, 2022, 2023 Peter Doornbosch
 *
 * This file is part of Kwik, an implementation of the QUIC protocol in Java.
 *
 * Kwik is free software: you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the
 * Free Software Foundation, either version 3 of the License, or (at your option)
 * any later version.
 *
 * Kwik is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
 * more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */


import java.nio.ByteBuffer;
import java.text.ParseException;

/**
 * Represents a crypto frame.
 * https://www.rfc-editor.org/rfc/rfc9000.html#name-crypto-frames
 */
public class CryptoFrame extends QuicFrame {

    private long offset;
    private int length;
    private byte[] cryptoData;
    private byte[] bytes;

    @Override
    public int getFrameLength() {
        return 0;
    }

    public QuicFrame parse(ByteBuffer buffer) throws ParseException{
        buffer.get();

        offset = parseLong(buffer);
        length = parsed(buffer);

        cryptoData = new byte[length];
        buffer.get(cryptoData);

        return this;
    }

    public static long parseLong(ByteBuffer buffer) throws ParseException {
        if (buffer.remaining() < 1) {
            throw new ParseException("Not enough bytes to parse long", 0);
        }

        long value;
        byte firstLengthByte = buffer.get();
        switch ((firstLengthByte & 0xc0) >> 6) {
            case 0:
                value = firstLengthByte;
                break;
            case 1:
                if (buffer.remaining() < 1) {
                    throw new ParseException("Not enough bytes to parse long", 0);
                }
                buffer.position(buffer.position() - 1);
                value = buffer.getShort() & 0x3fff;
                break;
            case 2:
                if (buffer.remaining() < 3) {
                    throw new ParseException("Not enough bytes to parse long", 0);
                }
                buffer.position(buffer.position() - 1);
                value = buffer.getInt() & 0x3fffffff;
                break;
            case 3:
                if (buffer.remaining() < 7) {
                    throw new ParseException("Not enough bytes to parse long", 0);
                }
                buffer.position(buffer.position() - 1);
                value = buffer.getLong() & 0x3fffffffffffffffL;
                break;
            default:
                // Impossible, just to satisfy the compiler
                throw new RuntimeException();
        }
        return value;
    }

    private int parsed(ByteBuffer data) throws ParseException {
        long value = parseLong(data);
        if (value <= Integer.MAX_VALUE) {
            return (int) value;
        } else {
            throw new IllegalArgumentException("value to large for Java int");
        }
    }

    public long getOffset() {
        return offset;
    }

    public void setOffset(long offset) {
        this.offset = offset;
    }

    public int getLength() {
        return length;
    }

    public void setLength(int length) {
        this.length = length;
    }

    public byte[] getCryptoData() {
        return cryptoData;
    }

    public void setCryptoData(byte[] cryptoData) {
        this.cryptoData = cryptoData;
    }

    public byte[] getBytes() {
        return bytes;
    }

    public void setBytes(byte[] bytes) {
        this.bytes = bytes;
    }
}
